//utf-8
#include "msg.h"
#include "rfmesh.h"




struct rfmesh_t *rfmesh = NULL;



static int find_next_hop(int id)
{
    if(rfmesh->route_table[id]){
        //tr("find_next_hop(%d) = %d\n",id,route_table[id]);
        return rfmesh->route_table[id];
    }else{
        //tr("find_next_hop(%d) = %d\n",id,context.prev);
        return rfmesh->prev;
    }
}



int save_to_routetable(int id,int prev)
{
    
    if(prev == rfmesh->prev || id == CONFIG_MESH_GATEWAY_ID){
        return 0;
    }
    //tr("insert route[%d]=[%d]\n",id,prev);
	ENTER_SAFE_AREA();
	rfmesh->route_table[id] = prev;
	rfmesh->rtv[id] = CONFIG_ROUTE_TIMEOUT;
	EXIT_SAFE_AREA();
    return 0;
}



void rfmesh_init(uint8_t id)
{

	rfmesh = OS_MALLOC(sizeof(struct rfmesh_t));
	rfmesh->level = 0xFF;
	rfmesh->id = id;

	INIT_LIST_HEAD(&rfmesh->txlist);
	INIT_LIST_HEAD(&rfmesh->rxlist);

	rfmesh->dhcp = 1;
	rfmesh->kalive = CONFIG_ROUTE_TIMEOUT;

	if(id == CONFIG_MESH_GATEWAY_ID){
			rfmesh->mesh = 1;
			rfmesh->dhcp = 0;
			rfmesh->prev = 1;
			rfmesh->level = 1;
	}
	
	message_init(rfwrite);

}


//PHY 接收到数据时先使用该接口缓存起来
int copyto_rxlist(int8_t rssi, struct frame_t *pframe)
{
	struct xfer_pool_t *pxfer = OS_MALLOC(sizeof(struct xfer_pool_t));
	if(pxfer == NULL)return -1;
	
	pxfer->rssi = rssi;
	memcpy(&pxfer->frame,pframe,sizeof(struct frame_t));

	ENTER_SAFE_AREA();
	list_add(&pxfer->list,&rfmesh->rxlist);
	EXIT_SAFE_AREA();
	
	return 0;
}


void mesh_linkdown(char *desc)
{
	if(rfmesh->id == CONFIG_MESH_GATEWAY_ID) return ;    //网关永不断线
	if(rfmesh->dhcp == 0) return ;                       //手动网络
	
	tr("link down: %s\n",desc);
	ENTER_SAFE_AREA();
	rfmesh->prev = 0;
	rfmesh->mesh = 0;
	rfmesh->level = 255;
	rfmesh->kalive = 0;
	EXIT_SAFE_AREA();
}


void rfmesh_output(void *pdata)
{
	extern void low_level_output( uint8_t *output);
	low_level_output((uint8_t *)pdata);
}

//协议栈处理完数据发送时先使用该接口缓存
//不同于copyto_rxlist 待发送数据会被task以周期进行重试发送
int copyto_txlist(struct frame_t *pframe,uint32_t timeout,uint32_t retry_cnt,int random)
{
	struct xfer_pool_t *pxfer = OS_MALLOC(sizeof(struct xfer_pool_t));
	if(pxfer == NULL)return -1;
	
	pxfer->retry = (retry_cnt)?retry_cnt:CONFIG_FRAME_RETRY_COUNT;
	memcpy(&pxfer->frame,pframe,sizeof(struct frame_t));
	pxfer->timeval = timeout;
	pxfer->timeout = timeout;
	
	//广播包如果没有dst回复则不会被取消，只会全部重试发出
	pxfer->serial = ( (pframe->receiver == 0xFF)?pframe->dst:pframe->receiver ) << 8;
	pxfer->serial |= pframe->msgid;
	
	//这里对一些数据进行了随机处理
	//需要注意 pxfer->retry 值  = 实际重试次数 + 1  目的是为了在最后一个重试时 检测出超时
	if(random && pxfer->retry == 1){
		pxfer->retry += 1;//这里按正常逻辑 +1 
		pxfer->timeout = rng(timeout);    //在随机值后发送
		pxfer->timeval = timeout;         //因为仅发送一次，该值无效
	
	}else{
		//这里pxfer->retry 并没有 +1 而是发送一次 没有 -1
		//如果一次直接发，多次在随后发出
		rfmesh_output(&pxfer->frame);
	}
	
	
	ENTER_SAFE_AREA();
	list_add(&pxfer->list,&rfmesh->txlist);
	EXIT_SAFE_AREA();
	
	
	return 0;
}



//txlist发送后如果收到回复则会删除该serial number表示的剩余待发送次数 删除数据即表示不在重试
int remove_from_xferpool(uint16_t serial)
{
	
	  struct list_head *cur,*tmp;
		list_for_each_safe(cur,tmp,&rfmesh->txlist){
		struct xfer_pool_t *pxfer = list_entry(cur,struct xfer_pool_t,list);
		//struct frame_t *pframe = (void *)&pxfer->frame;
			if(pxfer->serial == serial){
				ENTER_SAFE_AREA();
				//tr("remove %d\n",pxfer->retry);
				list_del(&pxfer->list);
				EXIT_SAFE_AREA();
				OS_FREE(pxfer);
				return 0;
			}
		}
	

    return -1;
}



//接收到数据会缓存其标记，避免重复向上层多次报告数据 因为发送端是 重试-等待回复 机制
int record_insert(uint8_t id,uint8_t sn)
{
    static uint32_t index = 0;
    //uint32_t record = dst<<24|src<<16|id << 8 | sn ;
    uint16_t record = id << 8 | sn ;
    //tr("record: [%02X %02X]\n",id,sn);

    for(int i=0;i<CONFIG_RECORDPOOL;i++){
        if(record == rfmesh->hop_record[i]){
            //tr("has\n");
            return 1;            
        }
    }
    
    rfmesh->hop_record[index++] = record;
    index = index % CONFIG_RECORDPOOL;

    return 0;
}

//确认收到
void confirm(uint8_t id,uint8_t sn)
{
    struct frame_t *pframe = OS_MALLOC(sizeof(struct frame_t));
    memset(pframe->payload,0x00,32);
    //frame.receiver = find_next_hop(id);
    pframe->receiver = (id);
    pframe->relay = rfmesh->id;
    pframe->dst = id;
    pframe->src = rfmesh->id;
    //tr("send confirm(receiver=%d dst=%d)\n", frame.receiver,id);
    pframe->flag = 0;
    pframe->msgid = rfmesh->msgid ++;
    pframe->type = MT_CONFIRM;
    pframe->payload[0] = sn;
    uint16_t crc =  \
    MBCRC16((unsigned char *)pframe,sizeof(struct frame_t) - 2);
    pframe->crc_h = (crc >> 8) & 0xFF;
    pframe->crc_l = (crc >> 0) & 0xFF;
    copyto_txlist(pframe,CONFIG_CONFIRM_INTERVAL,1,0);//需要立即回复
	OS_FREE(pframe);
}

//回复心跳 实际名称应该说是 heartbeat_ack
void ack(uint8_t id)
{
    struct frame_t *pframe = OS_MALLOC(sizeof(struct frame_t));
    pframe->receiver = find_next_hop(id);
    pframe->relay = rfmesh->id;
    pframe->dst = id;
    pframe->src = rfmesh->id;
    pframe->flag = 0;
    pframe->msgid = rfmesh->msgid ++;
    pframe->type = MT_ACK;
    pframe->payload[0] = rfmesh->level;
    uint16_t crc =  \
    MBCRC16((unsigned char *)pframe,sizeof(struct frame_t) - 2);
    pframe->crc_h = (crc >> 8) & 0xFF;
    pframe->crc_l = (crc >> 0) & 0xFF;
	copyto_txlist(pframe,CONFIG_CONFIRM_INTERVAL,0,0);//需要立即回复
	OS_FREE(pframe);
}
//心跳目的节点不是直接给网关的，需要被中继 任何中继都应该转发给下一级路由 直到网关
void heartbeat(uint8_t to)
{
    struct frame_t *pframe = OS_MALLOC(sizeof(struct frame_t));
    if(rfmesh->prev == rfmesh->id)return ;
    
    pframe->receiver = to;// find_next_hop(1);
    pframe->relay = rfmesh->id;
    pframe->dst = CONFIG_MESH_GATEWAY_ID;
    pframe->src = rfmesh->id;
    pframe->msgid = rfmesh->msgid ++;
    pframe->flag = 0;
    pframe->type = MT_HEARTBEAT;
    memset(pframe->payload,0x00,32);
	//tr("send heartbeat(to=%d msgid=%d)\n",to,pframe->msgid);
	
    uint16_t crc = MBCRC16((unsigned char *)pframe,sizeof(struct frame_t) - 2);
    pframe->crc_h = (crc >> 8) & 0xFF;
    pframe->crc_l = (crc >> 0) & 0xFF;
	copyto_txlist(pframe,CONFIG_CONFIRM_INTERVAL,0,0);//单包发送接收到16ms，考虑主机比较忙需要多次等待才能发出,取值1.5倍延时时间= 24ms
    OS_FREE(pframe);
}

//测试用
void ping(uint8_t id)
{
    struct frame_t *pframe = OS_MALLOC(sizeof(struct frame_t));
    pframe->receiver = find_next_hop(id);
    pframe->relay = rfmesh->id;
    pframe->dst = id;
    pframe->src = rfmesh->id;
    pframe->msgid = rfmesh->msgid ++;
    pframe->flag = 0;
    pframe->type = MT_PING;
    
    uint16_t crc =  \
    MBCRC16((unsigned char *)pframe,sizeof(struct frame_t) - 2);
    pframe->crc_h = (crc >> 8) & 0xFF;
    pframe->crc_l = (crc >> 0) & 0xFF;
    copyto_txlist(pframe,CONFIG_CONFIRM_INTERVAL,0,0);
	OS_FREE(pframe);
}
//message 底层发送
void rfwrite(uint8_t id, void *pdata)
{
    struct frame_t *pframe = OS_MALLOC(sizeof(struct frame_t));
    pframe->receiver = find_next_hop(id);
    pframe->relay = rfmesh->id;
    pframe->dst = id;
    pframe->src = rfmesh->id;
    pframe->msgid = rfmesh->msgid ++;
    pframe->type = MT_DATA;
    memcpy(pframe->payload,pdata,32);
    
    uint16_t crc =  \
    MBCRC16((unsigned char *)pframe,sizeof(struct frame_t) - 2);
    pframe->crc_h = (crc >> 8) & 0xFF;
    pframe->crc_l = (crc >> 0) & 0xFF;
    copyto_txlist(pframe,CONFIG_CONFIRM_INTERVAL,0,0);
    OS_FREE(pframe);
}

//广播路由信息
void broadcast_route(uint8_t random)
{
	
	HAL_GPIO_WritePin(GPIOA,GPIO_PIN_3,0);
    struct frame_t *pframe = OS_MALLOC(sizeof(struct frame_t));
    pframe->receiver = 0xFF;
    pframe->relay = rfmesh->id;
    pframe->src = rfmesh->id;
    pframe->dst = 0xFF;
    pframe->msgid = rfmesh->msgid ++;
    pframe->flag = 0;
    pframe->type = MT_ROUTE;
    pframe->payload[0] = ( rfmesh->id == CONFIG_MESH_GATEWAY_ID?1:rfmesh->level);
    pframe->payload[1] = ( rfmesh->mesh );
    
    uint16_t crc =  \
    MBCRC16((unsigned char *)pframe,sizeof(struct frame_t) - 2);
    pframe->crc_h = (crc >> 8) & 0xFF;
    pframe->crc_l = (crc >> 0) & 0xFF;
	//tr("broadcast_route(msgid=%d)\n",pframe->msgid);
    copyto_txlist(pframe,CONFIG_CONFIRM_INTERVAL,1,random);
    OS_FREE(pframe);
	HAL_GPIO_WritePin(GPIOA,GPIO_PIN_3,1);
	
}


void rfmesh_task(void)
{
	message_server();
	
    rfmesh->heartbeat_tv += CONFIG_TASK_INTERVAL_MS;//心跳时间
    rfmesh->routetable_tv += CONFIG_TASK_INTERVAL_MS;//路由表自减超时
	
    
		if(rfmesh->heartbeat_tv > CONFIG_HEARTBEAT_INTERVAL){
			rfmesh->heartbeat_tv = 0;
			
			//未组网不发送路由信息
			if(rfmesh->mesh == 0) return;
			
			//网关周期广播路由 其他设备周期心跳
			if(rfmesh->id == CONFIG_MESH_GATEWAY_ID){
				broadcast_route(0);
			}else{
				heartbeat(rfmesh->prev);
			}
			
		}
	
	
    //自减路由超时值，减到零删除路由记录
    if(rfmesh->routetable_tv >= ( CONFIG_HEARTBEAT_INTERVAL )){
        rfmesh->routetable_tv = 0 ;
			
			
				//遍历路由表超时 rfmesh->rtv 用于删除 路由表内不活跃设备
        for(int i=0;i< CONFIG_ROUTETABLE_SIZE;i++){
					
			ENTER_SAFE_AREA();
					
            if(rfmesh->rtv[i] >0){
                rfmesh->rtv[i] --;
            }
						
			if(rfmesh->rtv[i] == 0){
				rfmesh->route_table[i] = 0;
				rfmesh->rssi[i] = 0;
			}

			EXIT_SAFE_AREA();

        }
				
				//自身组网超时次数自减 用于删除自己心跳多次无法组网状态  也就是N次心跳未收到回复则标记断网
				if(rfmesh->id != CONFIG_MESH_GATEWAY_ID){
					
					ENTER_SAFE_AREA();
					
					if(rfmesh->kalive >0){
						rfmesh->kalive --;
					}
					
					if(rfmesh->kalive == 0){
						mesh_linkdown("kalive");
					}
					
					EXIT_SAFE_AREA();
					
				}
				
    }

    

    
		//断网不影响数据收发
		//接收数据处理
	  struct list_head *cur,*tmp;
		list_for_each_safe(cur,tmp,&rfmesh->rxlist){
				struct xfer_pool_t *pxfer = list_entry(cur,struct xfer_pool_t,list);
				struct frame_t *pframe = &pxfer->frame;

				uint16_t crc_local = MBCRC16((uint8_t *)pframe,sizeof(struct frame_t) -2);
				uint16_t crc_data = pframe->crc_h<<8|pframe->crc_l;
				if(crc_local == crc_data){
					//验证是否需要保护
					rfmesh_input(pframe);
				}else{
					//tr("crc error\n");
					ENTER_SAFE_AREA();
					rfmesh->crcerr ++;
					EXIT_SAFE_AREA();
				}
				ENTER_SAFE_AREA();
				list_del(&pxfer->list);
				EXIT_SAFE_AREA();
				OS_FREE(pxfer);
			
		}
		
		//发送数据处理
		list_for_each_safe(cur,tmp,&rfmesh->txlist){
		struct xfer_pool_t *pxfer = list_entry(cur,struct xfer_pool_t,list);
        //uint8_t msg_type = ((struct frame_t *)pxfer->buffer)->type ;
        uint8_t msg_type = pxfer->frame.type ;

        if(pxfer->retry > 1){
            
            if(pxfer->timeval >0){
                pxfer->timeval -= CONFIG_TASK_INTERVAL_MS;
            }else{
                pxfer->retry --;
                pxfer->timeval = pxfer->timeout / 2 + rng(pxfer->timeout);
				rfmesh_output(&pxfer->frame);

            }
            
        }else
        if(pxfer->retry == 1){//帧发送超时, 判定断网
			//这里不一定是超时导致，比如仅发送一次，在这里就会直接删除
			//正常发送10次 实际是10 +1 次，最后一次用来标记超时
            //tr("timeout %d\n",msg_type);
            ENTER_SAFE_AREA();
			list_del(&pxfer->list);
			EXIT_SAFE_AREA();
			OS_FREE(pxfer);

			//如果心跳包发送超时则标记断网
			//超时的意思是往下一级节点发送时未收到回复 而不是给网关未收到回复
            if(msg_type == MT_HEARTBEAT)
            {
				//uint8_t type = ((struct frame_t *)pxfer->buffer)->type ;
				//tr("mesh_linkdown type = %d\n",type);
				mesh_linkdown("timeout");
            }
						
        }
    }
		
}



void rfmesh_input(struct frame_t *pframe)
{

    /*
    recv    relay    src    dst
    00      x        x       x       无效
    FF      x        x       FF      广播包
    FF      x        x       x       广播转固定
    ID      x        x       ID      固定包
    ID      x        x       !ID     中继包
    */


 
    if(pframe->type == MT_ROUTE)//检测路由包
    {
		//tr("route from: %d\n",pframe->src);
        uint8_t host_level = pframe->payload[0];
			
        if( host_level < (rfmesh->level -1) && rfmesh->dhcp)
        {
			heartbeat(pframe->src);
        }else{
            //tr("save_to_routetable(rcv=%d dst=%d src=%d relay=%d)\n",pframe->receiver,pframe->dst, pframe->src,pframe->relay);
            save_to_routetable(pframe->src,pframe->relay);
        }
        return ;
    }
		
		
			int ret = record_insert(pframe->src,pframe->msgid);
			if(ret){
				//tr("record existing mt = %s\n",type[pframe->type]);//confirm = 6
				confirm(pframe->relay,pframe->msgid);//如果立即回复时未收到，此时再次回复，发送方最多发送三次
				return ;
			}

			save_to_routetable(pframe->src,pframe->relay);
			
			

        

			if(pframe->receiver == 0x00){
					tr("error format broadcast pack(src=%d dst=%d type=%d)\n",pframe->src,pframe->dst,pframe->type);
					return;
			}
			
			if(pframe->dst != rfmesh->id && pframe->receiver == 0xFF){
					tr("broadcast pack to fixed pack(src=%d dst=%d type=%d)\n",pframe->src,pframe->dst,pframe->type);
					return ;
			}


			if(pframe->receiver == rfmesh->id && pframe->dst != rfmesh->id){//hop package
					
					if(rfmesh->mesh == 0){
						//tr("link down,no hop\n");
						return ;
					}
					
					pframe->receiver = find_next_hop(pframe->dst);
					//tr("hop packet src=%x dst=%x receiver=%02X\n",pframe->src,pframe->dst,pframe->receiver);
				 
					confirm(pframe->relay,pframe->msgid);
					pframe->relay = rfmesh->id;
				
					if(pframe->type == MT_ACK){
						pframe->payload[0] = rfmesh->level;
					}
					uint16_t crc = MBCRC16((uint8_t*)pframe,sizeof(struct frame_t) - 2);
					pframe->crc_h = (crc >> 8) & 0xFF;
					pframe->crc_l = (crc >> 0) & 0xFF;
					copyto_txlist(pframe,CONFIG_CONFIRM_INTERVAL ,0,0);

					return ;
			}
			
			if(pframe->dst != rfmesh->id){
					tr("don't give me packet\n");
					return ;
			}
			
			
			if(pframe->type == MT_ACK){
				
					uint8_t level = pframe->payload[0];
				
					ENTER_SAFE_AREA();
					rfmesh->mesh = 1;
					rfmesh->kalive = CONFIG_ROUTE_TIMEOUT;
					if(rfmesh->dhcp){
						rfmesh->level = level +1;
						rfmesh->prev = pframe->relay;
					}
					EXIT_SAFE_AREA();
					confirm(pframe->relay,pframe->msgid);
					broadcast_route(1);
					
					return ;
			} 
			
			if(pframe->type == MT_HEARTBEAT){

					//只有网关会收到这个消息并回复，中间都是hop
					//tr("heartbeat packet: src=%d\n",pframe->src);
					if(rfmesh->id != CONFIG_MESH_GATEWAY_ID) return;
				
					ack(pframe->src);
					confirm(pframe->relay,pframe->msgid);
					return ;
			}
			
			if(pframe->type == MT_PING){
					//tr("ping packet code: %02X\n",pframe->msgid);
					confirm(pframe->relay,pframe->msgid);
					return ;
			}
			
			if(pframe->type == MT_CONFIRM){
					//tr("confirm(relay=%d,src=%d)\n",pframe->relay,pframe->src);
					remove_from_xferpool(pframe->relay<<8|pframe->payload[0]);
					return ;
			}

			

			if(pframe->type == MT_DATA){
					confirm(pframe->relay,pframe->msgid);
					message_input(pframe->src,(void *)pframe->payload);
					return ;
			}

    
}



